#pragma once

#include "BasicTypes.h"

#include <string>

namespace MOE
{
    namespace Core
    {
        class ClassMeta;
        class Type;

        // An object defining a member field in a class.
        class Field
        {
		public:
			static const Field kInvalid;

        public:
			// Default constructor. Constructs an invalid field that has Nil class as its parent class.
			Field();

            // Constructs the field under parentClass.
            Field(const ClassMeta& parentClass, const char8* fieldName, const Type& fieldType, tSize startingOffset);

			// Checks if this is not a default-constructed "invalid" field.
			bool IsValid() const;

            // Gets the class meta containing this field.
			const ClassMeta& GetClassMeta() const { return mParentClass; }

            // Gets the name of the field.
			const char8* GetName() const { return mFieldName.c_str(); }

            // Gets the type of the field.
			const Type& GetType() const { return mType; }

            // Gets the starting offset of this field into its parent object.
			tSize GetStartingOffset() const { return mStartingOffset; }

			// Get the reference of the field from classObject.
			tUntypedConstRef GetFieldRef(tUntypedConstRef classObject) const;
			tUntypedRef GetFieldRef(tUntypedRef classObject) const;

			// Read field value from object, and write it to destination. Destination must be able to hold the size of Type.
			void ReadValue(tUntypedConstRef classObject, tUntypedRef valueDestination) const;

			// Write the value from source to the field on object.
			void WriteValue(tUntypedConstRef valueSource, tUntypedRef classObject) const;

		private:
			const ClassMeta& mParentClass;
			std::string mFieldName;
			const Type& mType;
			tSize mStartingOffset;
        };
    }
}